package com.huangguolin.cloud.file.service.impl;

import com.huangguolin.cloud.file.entity.SearchFileEntity;
import com.huangguolin.cloud.file.repository.FileDao;
import com.huangguolin.cloud.file.service.FileService;
import com.huangguolin.cloud.login.entity.loginUserEntity;
import com.huangguolin.cloud.mybatis.entity.PtFileEntity;
import com.huangguolin.cloud.mybatis.flexigrid.PadingRstEntity;
import com.huangguolin.cloud.mybatis.flexigrid.PagingEntity;
import com.huangguolin.cloud.mybatis.ztree.ZtreeEntity;
import com.huangguolin.cloud.spring.util.QRCodeUtil;
import com.obs.services.ObsClient;
import com.obs.services.model.*;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class FileServiceImpl implements FileService {
    @Resource
    private FileDao fileDao;

    @Value("${endpoint}")
    private String endpoint;
    @Value("${access.key.id}")
    private String accessKeyId;
    @Value("${secret.access.key}")
    private String secretAccessKey;
    @Value("${bucket.name}")
    private String bucketName;
    @Resource
    private HttpSession httpSession;

    @Bean
    public ObsClient obsClient() {
        return new ObsClient(accessKeyId, secretAccessKey, endpoint);
    }

    @Override
    public PadingRstEntity<PtFileEntity> queryFileListByPage(SearchFileEntity search, PagingEntity paging) {

        PadingRstEntity<PtFileEntity> ptFileEntityPadingRstEntity = new PadingRstEntity<>();
        search.deal();
        paging.dealColums(PtFileEntity.class);
        ptFileEntityPadingRstEntity.setPage(paging.getPage());
        List<PtFileEntity> list = fileDao.queryFileListByPage(search,paging);
        Integer total = fileDao.queryFileTotal(search);
        ptFileEntityPadingRstEntity.setRawRecords(list);
        ptFileEntityPadingRstEntity.setTotal(total);
        ptFileEntityPadingRstEntity.putItem();
        return ptFileEntityPadingRstEntity;
    }

    @Override
    public void synchFileData() {//文件同步
        //通过令牌获取user_uuid
        String lang = LocaleContextHolder.getLocale().toString();
        loginUserEntity loginUserEntity = (loginUserEntity) SecurityContextHolder.getContext()
                .getAuthentication()
                .getPrincipal();
        String userUuid = loginUserEntity.getUserUuid();
        ObsClient obsClient = new ObsClient(accessKeyId,secretAccessKey,endpoint);
        ObjectListing list = obsClient.listObjects(bucketName);
        List<ObsObject> listObjects = list.getObjects();
        String obsKey;//obs文件信息
        Long obsSize;//obs文件大小
        List<PtFileEntity> ptFileEntityList = new ArrayList<>();
        PtFileEntity ptFileEntity = null;
        //文件浏览
        for(ObsObject obsObject:listObjects){
            ptFileEntity = new PtFileEntity();
            ptFileEntityList.add(ptFileEntity);
            obsKey = obsObject.getObjectKey();
            obsSize =  obsObject.getMetadata().getContentLength();
            ptFileEntity.setFilePath(obsKey);
            ptFileEntity.setFileCapacity(obsSize);
            ptFileEntity.setUserUuid(userUuid);
            if (isDir(obsKey)){
                ptFileEntity.setFileType(FILE_TYPE_DIR);//设置文件类型
            }
            ptFileEntity.setFileName(getFileName(obsKey));//获取文件名
        }

        List<PtFileEntity> ptFileEntityListDB = fileDao.queryFileList();

        for (PtFileEntity ptFileEntity1: ptFileEntityList){
            if (ptFileEntityListDB.contains(ptFileEntity1)){
                fileDao.updateFile(ptFileEntity1);
            }else{
                fileDao.insertFile(ptFileEntity1);
            }
        }

        for (PtFileEntity ptFileEntityDB: ptFileEntityListDB){
            if (!ptFileEntityList.contains(ptFileEntityDB)){
                fileDao.deleteFileByPath(ptFileEntityDB.getFilePath());
            }
        }

        ptFileEntityListDB = fileDao.queryFileList();
        for(PtFileEntity item:ptFileEntityListDB) {
            for (PtFileEntity parent:ptFileEntityListDB){
                if (isParentDir(item.getFilePath(),parent.getFilePath())){
                    item.setParentUuid(parent.getFileUuid());
                }
            }
        }

        for (PtFileEntity item:ptFileEntityListDB){
            fileDao.updateFileParentId(item);
        }

    }

    @Override
    public void copyFileDate() {

    }

    @Override
    public void queryFileByClick() {

    }


    //文件下载
    @Override
    public ResponseEntity<byte[]> downloadFile(String fileUuid) {
        PtFileEntity ptFileEntity = fileDao.queryFileById(fileUuid);

        if (ptFileEntity == null )
        {
            return null;
        }
        ObsClient obsClient = new ObsClient(accessKeyId,secretAccessKey,endpoint);
        ObsObject obsObject = obsClient.getObject(bucketName,ptFileEntity.getFilePath());
        InputStream is = obsObject.getObjectContent();
        byte[] block = new byte[1024];
        Integer length = 0;
        byte[] fileByte=null;
        try(ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ){
            while ((length = is.read(block)) > 0 ){
                byteArrayOutputStream.write(block,0,length);
                byteArrayOutputStream.flush();
            }
            fileByte=byteArrayOutputStream.toByteArray();
        }catch (IOException e1){
            e1.printStackTrace();
        }

        HttpHeaders headers =
                new HttpHeaders();
        headers.setContentDispositionFormData("attachment",
                ptFileEntity.getFileName());//告知浏览器以下载方式打开
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);//设置 MIME 类型
        return new ResponseEntity<byte[]>(
                fileByte,
                headers,
                HttpStatus.CREATED);

    }

    @Override
    public PtFileEntity queryParentFileInfoById(String fileUuid) {
        PtFileEntity ptFileEntity = fileDao.queryParentFileById(fileUuid);
        if (ptFileEntity == null){
            return ptFileEntity;
        }
        PtFileEntity parentFileEntity = fileDao.queryParentFileById(ptFileEntity.getParentUuid());
        return parentFileEntity;
    }

    @Override
    public List<ZtreeEntity> queryFileZtreeall() {
        return fileDao.queryFileZtreeall();
    }



    //文件分享
    @Override
    public String getShareFileLink(String fileUuid, String validityDate) {
        PtFileEntity ptFileEntity = fileDao.queryParentFileById(fileUuid);
        if(ptFileEntity==null){
            return "";
        }
        ObsClient obsClient = new ObsClient(accessKeyId,secretAccessKey,endpoint);
        TemporarySignatureRequest request = new TemporarySignatureRequest();
        request.setBucketName(bucketName);
        request.setObjectKey(ptFileEntity.getFilePath());
        request.setRequestDate(new Date());
        try {
            Integer dateNum = Integer.parseInt(validityDate);
            request.setExpires(UTIL_DATE * dateNum);
        }catch (NumberFormatException e){
            return "";
        }
        TemporarySignatureResponse signature = obsClient.createTemporarySignature(request);
        String url = signature.getSignedUrl();
        httpSession.setAttribute("shareLinkUrl",url);
        return url;

    }


    // 文件分享二维码
    @Override
    public ResponseEntity<byte[]> getQRCodeShare() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentDispositionFormData("attachment", "qrCode.png");//告知浏览器以下载方式打开
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);//设置 MIME 类型
        String shareLinkUrl = (String) httpSession.getAttribute("shareLinkUrl");
        byte[] fileByte = QRCodeUtil.generateQRCodeOut(shareLinkUrl).toByteArray();
        return new ResponseEntity<byte[]>(fileByte, headers, HttpStatus.CREATED);
    }
    //上传文件
    @Override
    public void uploadFile(String fileName, InputStream inputStream) {
        ObsClient obsClient = new ObsClient(accessKeyId,secretAccessKey,endpoint);
        obsClient.putObject(bucketName,fileName,inputStream);
        synchFileData();
    }

    //修改文件名
    @Override
    public void modifyFile(String fileName,String fileUuid) {
        PtFileEntity ptFileEntity = fileDao.queryParentFileById(fileUuid);
        if (ptFileEntity == null){
            return;
        }
        ObsClient obsClient = new ObsClient(accessKeyId,secretAccessKey,endpoint);
        ObsObject obsObject = obsClient.getObject(bucketName, ptFileEntity.getFilePath());
        InputStream inputStream = obsObject.getObjectContent();//保存到本地
        //判断远程是否存在，存在及删除
        if (obsClient.doesObjectExist(bucketName,ptFileEntity.getFilePath())){
            obsClient.deleteObject(bucketName,ptFileEntity.getFilePath());
        }
        String descObsKey = fileName;
        //判断是否为根目录
        if (!FILE_TYPE_DIR.equals(ptFileEntity.getParentUuid())){
            PtFileEntity parentEntity = fileDao.queryParentFileById(ptFileEntity.getParentUuid());
            if (parentEntity != null){
                //组装一下目的路径
                descObsKey = parentEntity.getFilePath() + fileName;
            }
        }
        obsClient.putObject(bucketName,descObsKey,inputStream);
        synchFileData();//同步数据
    }


    @Override
    public String getPreUrl(String fileUuid) {
        PtFileEntity ptFileEntity = fileDao.queryParentFileById(fileUuid);
        if (ptFileEntity == null){
            return  "";
        }
        ObsClient obsClient = new ObsClient(accessKeyId,secretAccessKey,endpoint);
        TemporarySignatureRequest request = new TemporarySignatureRequest();
        request.setBucketName(bucketName);
        request.setObjectKey(ptFileEntity.getFilePath());
        request.setRequestDate(new Date());
        request.setExpires(UTIL_HOURE);
        TemporarySignatureResponse signature = obsClient.createTemporarySignature(request);
        String url = signature.getSignedUrl();
        return url;
    }


    /**
     * 文件复制
     * @param fileUuid
     * @param pId
     * @return
     */
    @Override
    public PtFileEntity saveFileRefCopy(String fileUuid, String pId) {//文件复制
        PtFileEntity ptFileEntity = fileDao.queryParentFileById(fileUuid);
        if ( ptFileEntity==null ) {
            return ptFileEntity;
        }
        ObsClient obsClient = new ObsClient (accessKeyId,secretAccessKey,endpoint );
        ObsObject obsObject = obsClient.getObject (bucketName,ptFileEntity.getFilePath());
        InputStream inputStream = obsObject.getObjectContent();
        String descObsKey = ptFileEntity.getFileName();
        PtFileEntity moveFileEntity = fileDao.queryParentFileById(pId);
        if ( moveFileEntity == null ) {
            return ptFileEntity;
        }
        descObsKey = moveFileEntity.getFilePath()+descObsKey ;
        obsClient.putObject (bucketName,descObsKey,inputStream );
        synchFileData ();

        return ptFileEntity;
    }



    @Override
    public List<ZtreeEntity> queryAclZtree(String fileUuid) {


        List<ZtreeEntity> list = fileDao.queryAclZtree();

        PtFileEntity ptFileEntity = fileDao.queryParentFileById(fileUuid);
        if (ptFileEntity != null){
            ObsClient obsClient = new ObsClient(accessKeyId,secretAccessKey,endpoint);

            AccessControlList acl = obsClient.getObjectAcl(bucketName,ptFileEntity.getFilePath());
            for (ZtreeEntity ztreeEntity: list){
                for(GrantAndPermission grantAndPermission: acl.getGrantAndPermissions()){
                    if(ztreeEntity.getId().equals(grantAndPermission.getPermission().toString())){
                        ztreeEntity.setChecked(true);
                        break;
                    }
                }
            }
        }
        return list;
    }

    @Override
    public void setObjectAcl(String fileUuid, String aclArray) {
        PtFileEntity ptFileEntity = fileDao.queryParentFileById(fileUuid);
        if (ptFileEntity == null){
            return;
        }
        ObsClient obsClient = new ObsClient(accessKeyId,secretAccessKey,endpoint);
        AccessControlList acl = new AccessControlList();

        AccessControlList obsObject = obsClient.getBucketAcl(bucketName);
        Owner owner = obsObject.getOwner();
        acl.setOwner(owner);
        acl.grantPermission(new CanonicalGrantee(owner.getId()), Permission.PERMISSION_FULL_CONTROL);
        String[] acls = aclArray.split(",");
        for (String aclItem:acls){
            if(Permission.PERMISSION_READ.toString().equals(aclItem)){
                acl.grantPermission(GroupGrantee.ALL_USERS,Permission.PERMISSION_READ);
            }
            if(Permission.PERMISSION_WRITE.toString().equals(aclItem)){
                acl.grantPermission(GroupGrantee.ALL_USERS,Permission.PERMISSION_WRITE);
            }
            if(Permission.PERMISSION_READ_ACP.toString().equals(aclItem)){
                acl.grantPermission(GroupGrantee.ALL_USERS,Permission.PERMISSION_READ_ACP);
            }
            if(Permission.PERMISSION_WRITE_ACP.toString().equals(aclItem)){
                acl.grantPermission(GroupGrantee.ALL_USERS,Permission.PERMISSION_WRITE_ACP);
            }

        }
        obsClient.setObjectAcl(bucketName, ptFileEntity.getFilePath(), acl);
    }

    /**
     * 文件移动
     * @param fileUuid
     * @param pId
     * @return
     */
    @Override
    public PtFileEntity moveFileByBatch(String fileUuid, String pId) {
        PtFileEntity ptFileEntity = fileDao.queryParentFileById(fileUuid);
        if ( ptFileEntity==null ) {
            return ptFileEntity;
        }
        ObsClient obsClient = new ObsClient (accessKeyId,secretAccessKey,endpoint );
        ObsObject obsObject = obsClient.getObject (bucketName,ptFileEntity.getFilePath());

        InputStream inputStream = obsObject.getObjectContent();
        //判断原文件是否存在，存在则删除
        if(obsClient.doesObjectExist(bucketName,ptFileEntity.getFilePath())){
            obsClient.deleteObject(bucketName,ptFileEntity.getFilePath());

        }
        String descObsKey = ptFileEntity.getFileName();
        PtFileEntity moveFileEntity = fileDao.queryParentFileById(pId);
        if ( moveFileEntity == null ) {
            return ptFileEntity;
        }
        descObsKey = moveFileEntity.getFilePath()+descObsKey ;
        obsClient.putObject (bucketName,descObsKey,inputStream );
        synchFileData ();

        return ptFileEntity;

    }

    /**
     * 文件删除
     * @param fileUuid
     */
    @Override
    public void deleteFile(String fileUuid) {
        fileDao.deleteFile(fileUuid);
    }


    /**
     * 判断是否为目录
     * @param obsKey
     * @return
     */
    public  boolean isDir(String obsKey){

        int index = obsKey.lastIndexOf("/");
        //System.out.println(index);
        if (index == obsKey.length()-1){
            return true;
        }else{
            return  false;
        }
    }

    /**
     * 获取文件名称
     * @param obsKey
     * @return
     */
    public String getFileName(String obsKey){
        String fileName = obsKey;
        if (isDir(obsKey)){
            fileName = obsKey.substring(0,obsKey.length()-1);
        }
        int index = fileName.lastIndexOf("/");
        fileName = fileName.substring(index+1);
        return fileName;
    }

    /**
     * 判断是否为父目录
     * @param descObsKey 目录obsKey
     * @param parentObjsKey  父亲目录obsKey
     * @return
     */
    public boolean isParentDir(String descObsKey,String parentObjsKey) {
        if (parentObjsKey.length() < descObsKey.length()) {
            if (isDir(parentObjsKey)){
                Integer index = descObsKey.indexOf(parentObjsKey);
                if (index == 0){
                    return true;
                }
            }
        }
        return false;
    }


}